#!/usr/bin/perl

package get_child_features;

use strict;
use warnings;

use lib 'lib';
use base 'SADI::Simple::AsyncService';

#-----------------------------------------------------------------
# SERVICE CONFIGURATION PART
#-----------------------------------------------------------------

use SADI::GMOD::Config qw(
    get_base_url
    get_gmod_name
);

my %config = (

    ServiceName => sprintf('get_child_features%s', get_gmod_name() ? sprintf(' (%s)', get_gmod_name()) : ''),
    Description => 'get the child features of a given sequence feature',
    InputClass => 'http://sadiframework.org/ontologies/GMOD/Feature.owl#Feature',
    OutputClass => 'http://sadiframework.org/ontologies/GMOD/service/get_child_features.owl#OutputClass',   
    Authority => 'sadiframework.org', 
    Provider => 'ben.vvalk@gmail.com',
    URL => get_base_url . 'get_child_features', # only required for asynchronous services

);

#-----------------------------------------------------------------
# CGI HANDLER PART
#-----------------------------------------------------------------

use Log::Log4perl;

Log::Log4perl->init('log4perl.properties');

my $service = get_child_features->new;
$service->handle_cgi_request;

#-----------------------------------------------------------------
# SERVICE IMPLEMENTATION PART
#-----------------------------------------------------------------

use SADI::GMOD::Config qw(
    get_db_args
    get_gff_id_to_dbxref_mapping
);
use RDF::Trine::Node::Resource;
use RDF::Trine::Node::Literal;
use RDF::Trine::Statement;
use RDF::Trine::Parser;
use Bio::DB::SeqFeature::Store::Extended;
use Utils::Dbxref qw(
    id_type_to_dbxref
    get_feature_by_primary_dbxref
);
use Utils::BiopolymerRegion qw(parse_biopolymer_region);
use Utils::Trine qw(is_uri_resource);
use Vocab::SIO qw(SIO_ONTOLOGY_PREFIX);
use Utils::URI qw(parse_feature_uri);

=head2 new 

 Function: create a new instance of the service
 
=cut

sub new {
    my $class = shift;
    my $self = $class->SUPER::new(%config);
    bless($self, $class);
    return $self;
}

=head2 process_it

 Function: implements the business logic of a SADI service
 Args    : $inputs - ref to an array of RDF::Trine::Node::Resource
           $input_model - an RDF::Trine::Model containing the input RDF data
           $output_model - an RDF::Trine::Model containing the output RDF data
 Returns : nothing (service output is stored in $output_model)

=cut

sub process_it {

    my ($self, $inputs, $input_model, $output_model) = @_;

    my $log = Log::Log4perl->get_logger('get_feature_info');
    my $db = Bio::DB::SeqFeature::Store::Extended->new(get_db_args, -gff_id_to_dbxref => get_gff_id_to_dbxref_mapping);
    my $parser = RDF::Trine::Parser->new('turtle');
    my $templater = Template->new;
    my $has_part = RDF::Trine::Node::Resource->new(SIO_ONTOLOGY_PREFIX . 'SIO_000028');
    my $derives_into = RDF::Trine::Node::Resource->new(SIO_ONTOLOGY_PREFIX . 'SIO_000245');
    my %visited_features = ();

    foreach my $input (@$inputs) {

        next unless is_uri_resource($input);
        
        $log->info(sprintf('processing input %s', $input->uri));

        my $gff_id = parse_feature_uri($input->uri);
        next unless $gff_id;        

        my $it1 = $db->features(-attributes => { parent_id => $gff_id }, -iterator => 1);
        my $it2 = $db->features(-attributes => { Derives_from => $gff_id }, -iterator => 1);

        my @iterators = ($it1, $it2);
        my @properties = ($has_part, $derives_into); 

        #------------------------------------------------------------
        # encode the output RDF
        #------------------------------------------------------------

        for (my $i = 0; $i < @iterators; $i++) {

            my $it = $iterators[$i];
            my $property = $properties[$i];

            while (my $feature = $it->next_seq) {

                next unless $feature->uri;

                my $feature_node = RDF::Trine::Node::Resource->new($feature->uri);
                my $statement = RDF::Trine::Statement->new($input, $property, $feature_node);
                $output_model->add_statement($statement);

                if (!$visited_features{$feature->uri}) {
                    $parser->parse_into_model(undef, $feature->ttl, $output_model);
                    $visited_features{$feature->uri} = 1;
                }

                my $ref_feature = $feature->ref_feature;

                if (!$visited_features{$ref_feature->uri}) {
                    $parser->parse_into_model(undef, $ref_feature->ttl, $output_model);
                    $visited_features{$ref_feature->uri} = 1;
                }

            }
        }

    }
}

1;

__END__
